home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Bug Proofing Visual Basic: A Guide to Error Handling and Prevention
(Publisher: John Wiley & Sons, Inc.)
Author(s): Rod Stephens
ISBN: 0471323519
Publication Date: 11/01/98

Search this book:
 
Previous Table of Contents Next


This code can be restructured to remove the confusing Resume statement with a simpler Resume Next statement. The following routine moves the complex file reading code into the ReadData subroutine. If an error occurs inside ReadData, this routine uses the Resume Next statement to continue execution after ReadData. This code is easier to understand than the previous version.

Private Sub LoadData(ByVal file_name As String)
Dim fnum As Integer

    ‘ Open a file.
    fnum = FreeFile
    Open file_name For Input As #fnum

    ‘ Read from the file, process data, etc.
    On Error GoTo ReadError
    ReadData fnum

    ‘ Close the file.
    Close #fnum
    Exit Sub

ReadError:
    MsgBox “Error” & Str$(Err.Number) & _
        vbCrLf & Err.Description
    Resume Next
End Sub

Use GoTo to Simplify

GoTo is sometimes also used when the alternative would be more awkward and confusing. For example, a single GoTo statement can allow a program to break out of a deeply nested series of loops. The following code executes a series of loops. If it finds the condition value(i, j, k) = 0, it uses a GoTo statement to break out of all of the loops in one step.

Do While Timer < stop_time
    For i = 1 To 100
        For j = i + 1 To 1000
            ‘ Do something here.
                :
            If value(i, j) = 0 Then GoTo ExitLoops
        Next j
    Next i
Loop

ExitLoops:

Compare this to the following code that breaks out of the loops without using a GoTo statement. This code is reasonable, but the previous version is simpler.

Dim found_entry As Boolean

    found_entry = False
    Do While Timer < stop_time
        For i = 1 To 100
            For j = i + 1 To 1000
                ‘ Do something here.
                    :
                If value(i, j) = 0 Then
                    found_entry = True
                    Exit For
                End If
                if found_entry Then Exit For
            Next j
            if found_entry Then Exit For
        Next i
        if found_entry Then Exit Do
    Loop

Exit in One Place

Some developers believe that every routine should always exit from a single point. That makes it easy to verify that any special cleanup code is properly executed.

The following subroutine opens two data files and reads from them. It uses error handlers with appropriate Resume statements to ensure that it closes the files properly and always exits at the same Exit Sub statement.

Private Sub LoadData( _
    ByVal file_name1 As String, _
    ByVal file_name2 As String)

Dim fnum1 As Integer
Dim fnum2 As Integer

    ‘ Open the files.
    On Error GoTo OpenError1
    fnum1 = FreeFile
    Open file_name1 For Input As #fnum1

    On Error GoTo OpenError2
    fnum2 = FreeFile
    Open file_name1 For Input As #fnum2

    ‘ Read from the file, process data, etc.
    On Error GoTo ReadError
        :

    ‘ Close the files.
CloseFile1:
    On Error GoTo CloseError2
    Close #fnum2

CloseFile2:
    On Error GoTo CloseError1
    Close #fnum1

LoadDataDone:
    On Error Resume Next

    ‘ Always exit here.
    Exit Sub

    ‘ ******************************
    ‘ Error handlers (code omitted).
OpenError1:
        :
    Resume LoadDataDone

OpenError2:
        :
    Resume CloseFile1     ‘ Close file 1 only.

ReadError:
        :
    Resume CloseFile2     ‘ Close both files.

CloseError2:
        :
    Resume CloseFile1     ‘ Close file 1 only.

CloseError1:
        :
    Resume LoadDataDone   ‘ We’ve cleaned up all we can.
End Sub

Making a routine exit at a single point generally requires lots of error handlers, GoTos, and labeled lines. This example required six On Error statements, five error handlers, and eight labeled lines. This makes the routine look somewhat cluttered, but most of this code is required anyway, no matter how the routine is organized. The subroutine in this example must handle errors in quite a few situations. It must be prepared to close zero, one, or both of the files depending on which files are open. Handling all those situations makes the routine fairly complex in any case.

Exit before Error Handlers

Always place an Exit Sub statement before error-handling code so the routine does not continue past the end of the normal code and fall into the error handlers.

         :
    ‘ Done with normal processing.
    Exit Sub

    ‘ ***************
    ‘ Error handlers.
    ‘ ***************
OpenFileError:
        :

Place error handlers together at the end of the routine. Don’t mix error-handling code with normal code.

Don’t Use IIF

The IIF statement has the syntax

variable = IIF(expression, true_value, false_value)

Here, expression is a logical expression. This statement gives the variable the value true_value if the expression is True and false_value if it is False.

IIF is confusing so you should not use it. Use an If Then Else statement instead. The following code compares the times required by IIF and If Then Else. The If Then Else statement is not only easier to understand, it also takes only 25 percent as long as IIF.

Private Sub TimeIIF()
Const NUM_TESTS = 100000
Dim start_time As Single
Dim stop_time As Single
Dim i As Long
Dim txt As String

    ‘ Try IFF.
    start_time = Timer
    For i = 1 To NUM_TESTS
        txt = IIf(i < 5000, _
            “It’s a smaller value”, _
            “It’s a larger value”)
    Next i
    stop_time = Timer
    MsgBox Format$(stop_time - start_time, “0.00”)

    ‘ Try If Then Else.
    start_time = Timer
    For i = 1 To NUM_TESTS
        If i < 5000 Then
            txt = “It’s a smaller value”
        Else
            txt = “It’s a larger value”
        End If
    Next i
    stop_time = Timer
    MsgBox Format$(stop_time - start_time, “0.00”)
End Sub

IIF also has interacts strangely with routines that have side effects because it always evaluates both assignment values whether the condition is True or not. In the following code, IFF executes both TrueFunction and FalseFunction even though it does not really need the value of FalseFunction.

variable = IIF(True, TrueFunction, FalseFunction)

Prevent confusion by using If Then Else instead of IIF.

Watch for Overflow and Underflow

Watch out for expressions that can produce overflow or underflow. For example, the following function produces an overflow error if its input parameter is greater than 16383. It produces an underflow if the parameter is less than –16384.

Function DoubleIt(ByVal x As Integer) As Integer
    DoubleIt = 2 * x
End Function


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.